#include "KMNetServer.h"
#include <algorithm>

const unsigned int kMinimumPacketSize = 2;

KMNetServer::KMNetServer()
{
}

KMNetServer::~KMNetServer()
{
}

bool KMNetServer::listenTo(unsigned int port)
{
    std::cout << "starting server.." << std::endl;

    mAddress.host = ENET_HOST_ANY; // localhost
    mAddress.port = port;

    mHost = enet_host_create(
            &mAddress,  // the address to bind the server host to
            1000,       // allowed connections
            0,          // unlimited channel count
            0,          // assume any amount of incoming bandwidth
            0);         // assume any amount of outgoing bandwidth

    return mHost != 0;
}

void KMNetServer::stopListen()
{
    // - Disconnect all clients (close sockets)

    // TODO: probably there's a better way.
    ENetPeer *currentPeer;

    for (currentPeer = mHost->peers;
         currentPeer < &mHost->peers[mHost->peerCount];
         ++currentPeer)
    {
       if (currentPeer->state == ENET_PEER_STATE_CONNECTED)
       {
            enet_peer_disconnect(currentPeer, 0);
            enet_host_flush(mHost);
            enet_peer_reset(currentPeer);
       }
    }
    enet_host_destroy(mHost);
    // FIXME: memory leak on NetComputers

}

void KMNetServer::update(unsigned int timeout)
{
    ENetEvent event;

    while (enet_host_service(mHost, &event, timeout) > 0)
    {
        switch (event.type)
        {
            case ENET_EVENT_TYPE_CONNECT:
            {
                KMNetConnectedClient *client = new KMNetConnectedClient(event.peer);
                clientConnected(client);
                mConnectedClients.push_back(client);
                event.peer->data = (void *)client;
                break;
            }
            case ENET_EVENT_TYPE_RECEIVE:
            {
                KMNetConnectedClient *client =
                    static_cast<KMNetConnectedClient*>(event.peer->data);

                if (event.packet->dataLength >= kMinimumPacketSize)
                {
                    KMNetMsgIn msg((char *)event.packet->data,
                        event.packet->dataLength);

                    processMessageFromClient(client, msg);
                }

                enet_packet_destroy(event.packet);
                break;
            }
            case ENET_EVENT_TYPE_DISCONNECT:
            {
                KMNetConnectedClient *client =
                    static_cast<KMNetConnectedClient*>(event.peer->data);

                clientDisconnected(client);
                mConnectedClients.erase(std::find(mConnectedClients.begin(),
                                                  mConnectedClients.end(),
                                                  client));
                delete client;
                event.peer->data = NULL;
                break;
            }
            default: break;
        }
    }

}
